package com.qen.fx.custom.impl.pwd;

import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.digest.DigestAlgorithm;
import cn.hutool.crypto.digest.DigestUtil;
import cn.hutool.crypto.digest.Digester;
import com.qen.App;
import com.qen.fx.ViewIndex;
import com.qen.fx.custom.CustomBusiness;
import com.qen.fx.tools.ClipboardTool;
import com.qen.plugin.notification.NotificationTool;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.event.Event;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.control.ChoiceBox;
import javafx.scene.control.Label;
import javafx.scene.control.Separator;
import javafx.scene.control.TextArea;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;

import java.io.IOException;
import java.net.URL;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.Security;
import java.util.Base64;
import java.util.ResourceBundle;

public class HashTxt extends CustomBusiness {

    @FXML
    private Label sha384Label;
    @FXML
    private Label sha1Label;
    @FXML
    private Label sha512Label;
    @FXML
    private Label sha3Label;
    @FXML
    private Label sha224Label;
    @FXML
    private Label ripemd160Label;
    @FXML
    private Label md5Label;
    @FXML
    private Label sha256Label;
    @FXML
    private TextArea hashText;
    @FXML
    private ChoiceBox hashChoice;
    @FXML
    private VBox vBox;
    @FXML
    private Separator separatorLine;
    @FXML
    private HBox hBox1;
    @FXML
    private HBox hBox2;


    public HashTxt() {
        FXMLLoader fxmlLoader = new FXMLLoader(App.class.getResource(ViewIndex.HashTxtFXML));
        fxmlLoader.setRoot(this);
        fxmlLoader.setController(this);
        try {
            fxmlLoader.load();
        } catch (IOException e) {
            e.printStackTrace();
        }
        vBox.setPrefWidth(ViewIndex.contentPreferWidth);
        hashText.setPrefWidth(ViewIndex.contentPreferWidth-300);
        separatorLine.setPrefWidth(ViewIndex.contentPreferWidth-300);
        hashChoice.setPrefWidth(ViewIndex.contentPreferWidth-300);
        hBox1.setPrefWidth(ViewIndex.contentPreferWidth-300);
        hBox2.setPrefWidth(ViewIndex.contentPreferWidth-300);

        sha1Label.setPrefWidth(ViewIndex.contentPreferWidth-300);
        md5Label.setPrefWidth(ViewIndex.contentPreferWidth-300);
        sha3Label.setPrefWidth(ViewIndex.contentPreferWidth-300);
        sha384Label.setPrefWidth(ViewIndex.contentPreferWidth-300);
        sha512Label.setPrefWidth(ViewIndex.contentPreferWidth-300);
        sha224Label.setPrefWidth(ViewIndex.contentPreferWidth-300);
        ripemd160Label.setPrefWidth(ViewIndex.contentPreferWidth-300);
        sha256Label.setPrefWidth(ViewIndex.contentPreferWidth-300);

        String[] st = new String[]{"Binary (base 2)", "Hexadecimal (base 16)", "Base64 (base 64)", "Base64url (base 64 with url safe chars)"};
        HashTxt controller = fxmlLoader.getController();
        hashChoice.setItems(FXCollections.observableArrayList(st));
        hashChoice.setValue("Hexadecimal (base 16)");
        hashText.textProperty().addListener(new ChangeListener<Object>() {
            @Override
            public void changed(ObservableValue<?> observable, Object oldValue, Object newValue) {
                createHash();
            }
        });
    }

    @FXML
    public void initialize() {
    }

    @FXML
    public void changeChoiceHash(Event event) {
        createHash();
    }

    @FXML
    public void clickSha3(Event event) {
        copyStr(sha3Label);
    }

    private void copyStr(Label label) {
        String token = label.getText();
        if (StrUtil.isBlank(token)) {
            return;
        }
        ClipboardTool.copyToClipboard(token);
        NotificationTool.message("复制成功!");
    }

    @FXML
    public void clickMd5(Event event) {
        copyStr(md5Label);
    }

    @FXML
    public void clickSha1(Event event) {
        copyStr(sha1Label);
    }

    @FXML
    public void clickSha512(Event event) {
        copyStr(sha512Label);
    }

    @FXML
    public void clickSha224(Event event) {
        copyStr(sha224Label);
    }

    @FXML
    public void clickSha256(Event event) {
        copyStr(sha256Label);
    }

    @FXML
    public void copyRipemd160(Event event) {
        copyStr(ripemd160Label);
    }

    @FXML
    public void clickSha384(Event event) {
        copyStr(sha384Label);
    }

    @Override
    public VBox init() {
        return null;
    }

    @Override
    public void initialize(URL url, ResourceBundle resourceBundle) {
    }

    private void createHash() {
        String hashTextValue = hashText.getText();
        if (StrUtil.isBlank(hashTextValue)) {
            return;
        }
//        "Binary (base 2)", "Hexadecimal (base 16)", "Base64 (base 64)", "Base64url (base 64 with url safe chars)"
        String hashChoiceValue = hashChoice.getValue().toString().trim();
        if (StrUtil.isBlank(hashChoiceValue)) {
            hashChoiceValue = "Hexadecimal (base 16)";
        }
        String md5 = "";
        String sha1 = "";
        String sha256 = "";
        String sha224 = "";
        String sha512 = "";
        String sha384 = "";
        String sha3 = "";
        String ripemd160 = "";
        if ("Binary (base 2)".equals(hashChoiceValue)) {
            md5 = binary2md5(hashTextValue);
            sha1 = binary2sha1(hashTextValue);
            sha256 = binary2sha256(hashTextValue);
            sha224 = binary2sha224(hashTextValue);
            sha512 = binary2sha512(hashTextValue);
            sha384 = binary2sha384(hashTextValue);
            sha3 = binary2sha3(hashTextValue);
            ripemd160 = binary2ripemd160(hashTextValue);
        } else if ("Hexadecimal (base 16)".equals(hashChoiceValue)) {
            md5 = hexadecimal2md5(hashTextValue);
            sha1 = hexadecimal2sha1(hashTextValue);
            sha256 = hexadecimal2sha256(hashTextValue);
            sha224 = hexadecimal2sha224(hashTextValue);
            sha512 = hexadecimal2sha512(hashTextValue);
            sha384 = hexadecimal2sha384(hashTextValue);
            sha3 = hexadecimal2sha3(hashTextValue);
            ripemd160 = hexadecimal2ripemd160(hashTextValue);
        } else if ("Base64 (base 64)".equals(hashChoiceValue)) {
            md5 = base642md5(hashTextValue);
            sha1 = base642sha1(hashTextValue);
            sha256 = base642sha256(hashTextValue);
            sha224 = base642sha224(hashTextValue);
            sha512 = base642sha512(hashTextValue);
            sha384 = base642sha384(hashTextValue);
            sha3 = base642sha3(hashTextValue);
            ripemd160 = base642ripemd160(hashTextValue);
        } else if ("Base64url (base 64 with url safe chars)".equals(hashChoiceValue)) {
            md5 = base64url2md5(hashTextValue);
            sha1 = base64url2sha1(hashTextValue);
            sha256 = base64url2sha256(hashTextValue);
            sha224 = base64url2sha224(hashTextValue);
            sha512 = base64url2sha512(hashTextValue);
            sha384 = base64url2sha384(hashTextValue);
            sha3 = base64url2sha3(hashTextValue);
            ripemd160 = base64url2ripemd160(hashTextValue);
        }
        md5Label.setText(md5);
        sha1Label.setText(sha1);
        sha256Label.setText(sha256);
        sha224Label.setText(sha224);
        sha512Label.setText(sha512);
        sha384Label.setText(sha384);
        sha3Label.setText(sha3);
        ripemd160Label.setText(ripemd160);
    }

    private String binary2md5(String hashTextValue) {
        return str2Pwd("base2", "MD5", hashTextValue);
    }

    private String binary2sha1(String hashTextValue) {
        return str2Pwd("base2", "SHA-1", hashTextValue);
    }

    private String binary2sha256(String hashTextValue) {
        return str2Pwd("base2", "SHA-256", hashTextValue);
    }

    private String binary2sha224(String hashTextValue) {
        return str2Pwd("base2", "SHA-224", hashTextValue);
    }

    private String binary2sha512(String hashTextValue) {
        return str2Pwd("base2", "SHA-512", hashTextValue);
    }

    private String binary2sha384(String hashTextValue) {
        return str2Pwd("base2", "SHA-384", hashTextValue);
    }

    private String binary2sha3(String hashTextValue) {
        return str2Pwd("base2", "SHA3-256", hashTextValue);
    }

    private String binary2ripemd160(String hashTextValue) {
        return str2Pwd("base2", "RIPEMD160", hashTextValue);
    }

    private String hexadecimal2md5(String hashTextValue) {
        return DigestUtil.md5Hex(hashTextValue);
    }

    private String hexadecimal2sha1(String hashTextValue) {
        return DigestUtil.sha1Hex(hashTextValue);
    }

    private String hexadecimal2sha256(String hashTextValue) {
        return DigestUtil.sha256Hex(hashTextValue);
    }

    private String hexadecimal2sha224(String hashTextValue) {
        return (new Digester("SHA-224")).digestHex(hashTextValue, "UTF-8");
    }

    private String hexadecimal2sha512(String hashTextValue) {
        return DigestUtil.sha512Hex(hashTextValue);
    }

    private String hexadecimal2sha384(String hashTextValue) {
        return (new Digester(DigestAlgorithm.SHA384)).digestHex(hashTextValue, "UTF-8");
    }

    private String hexadecimal2sha3(String hashTextValue) {
        return (new Digester("SHA3-256")).digestHex(hashTextValue, "UTF-8");
    }

    private String hexadecimal2ripemd160(String hashTextValue) {
        return str2Pwd("base16", "RIPEMD160", hashTextValue);
    }

    private String base642md5(String hashTextValue) {
        return str2Pwd("base64", "MD5", hashTextValue);
    }

    private String base642sha1(String hashTextValue) {
        return str2Pwd("base64", "SHA-1", hashTextValue);
    }

    private String base642sha256(String hashTextValue) {
        return str2Pwd("base64", "SHA-256", hashTextValue);
    }

    private String base642sha224(String hashTextValue) {
        return str2Pwd("base64", "SHA-224", hashTextValue);

    }

    private String base642sha512(String hashTextValue) {
        return str2Pwd("base64", "SHA-512", hashTextValue);

    }

    private String base642sha384(String hashTextValue) {
        return str2Pwd("base64", "SHA-384", hashTextValue);

    }

    private String base642sha3(String hashTextValue) {
        return str2Pwd("base64", "SHA3-256", hashTextValue);

    }

    private String base642ripemd160(String hashTextValue) {
        return str2Pwd("base64", "RIPEMD160", hashTextValue);
    }

    private String base64url2md5(String hashTextValue) {
        return str2Pwd("base64url", "MD5", hashTextValue);
    }

    private String base64url2sha1(String hashTextValue) {
        return str2Pwd("base64url", "SHA-1", hashTextValue);
    }

    private String base64url2sha256(String hashTextValue) {
        return str2Pwd("base64url", "SHA-256", hashTextValue);
    }

    private String base64url2sha224(String hashTextValue) {
        return str2Pwd("base64url", "SHA-224", hashTextValue);
    }

    private String base64url2sha512(String hashTextValue) {
        return str2Pwd("base64url", "SHA-512", hashTextValue);
    }

    private String base64url2sha384(String hashTextValue) {
        return str2Pwd("base64url", "SHA-384", hashTextValue);
    }

    private String base64url2sha3(String hashTextValue) {
        return str2Pwd("base64url", "SHA3-256", hashTextValue);
    }

    private String base64url2ripemd160(String hashTextValue) {
        return str2Pwd("base64url", "RIPEMD160", hashTextValue);
    }

    private String bytesToHex(byte[] bytes) {
        StringBuilder hexString = new StringBuilder();
        for (byte b : bytes) {
            String hex = Integer.toHexString(0xff & b);
            if (hex.length() == 1) {
                hexString.append('0');
            }
            hexString.append(hex);
        }
        return hexString.toString();
    }

    private String bytesToBinaryString(byte[] bytes) {
        StringBuilder res = new StringBuilder();
        for (byte b : bytes) {
            int val = b & 0xFF;
            for (int i = 7; i >= 0; --i) {
                res.append(((val >> i) & 0x01) == 0 ? '0' : '1');
            }
        }
        return res.toString();
    }

    private String str2Pwd(String type, String algorithm, String data) {
        try {
            MessageDigest digest = MessageDigest.getInstance(algorithm);
            byte[] hash = digest.digest(data.getBytes());
            if ("base2".equals(type)) {
                return bytesToBinaryString(hash);
            } else if ("base16".equals(type)) {
                return bytesToHex(hash);
            } else if ("base64".equals(type)) {
                return Base64.getEncoder().encodeToString(hash);
            } else if ("base64url".equals(type)) {
                return Base64.getUrlEncoder().withoutPadding().encodeToString(hash);
            }
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        return null;
    }

}